/*
https://wivl.github.io/blog/posts/cpp17-multi-thread-zero-to-threadpool/
锁
mutex 互斥锁
    #include <mutex>
    std::mutex safe_counter_mutex;  定义锁
    safe_counter_mutex.lock();  加锁
    safe_counter_mutex.unlock();   释放锁
    std::lock_guard
        如果忘记unlock()或者发生异常，就会死锁，所以更推荐用RAII风格
        void safe_increment(int times)
        {
            for (int i = 0; i < times; i++)
            {
                // safe_counter_mutex.lock(); // 加锁
                std::lock_guard<std::mutex> lock(safe_counter_mutex);  // 自动锁定和释放锁
                safe_counter++;
                // safe_counter_mutex.unlock(); // 释放锁
            }
        }
    std::unique_lock
      创建时可以不锁定（通过指定第二个参数为std::defer_lock），而在需要时再锁定, 作用域规则同 lock_grard，析构时自动释放锁
      条件变量需要该类型的锁作为参数（此时必须使用unique_lock）
      std::unique_lock<std::mutex> lock(safe_counter_mutex, sed::defer_lock);

原子操作
有两个线程，一个要写数据，一个读数据，如果不加锁，可能会造成读写值混乱，使用std::mutex程序执行不会导致混乱，但是每一次循环都要加锁解锁是的程序开销很大。
为了提高性能，C++11提供了原子类型(std::atomic<T>)，它提供了多线程间的原子操作，可以把原子操作理解成一种：不需要用到互斥量加锁（无锁）技术的多线程并发编程方式。
它定义在<atomic>头文件中，原子类型是封装了一个值的类型，它的访问保证不会导致数据的竞争，并且可以用于在不同的线程之间同步内存访问。
从效率上来说，原子操作要比互斥量的方式效率要高。

atomic常见成员函数：
  load()//读取数据
  store()//存储数据
  fetch_add(val)//加法
  fetch_sub(val)//减法
  exchange()//替换
*/
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
#include <atomic>

int counter = 0; // 无锁变量

int safe_counter = 0;          // 互斥锁变量
std::mutex safe_counter_mutex; // 互斥锁

std::atomic_int atomic_counter = 0; // 原子操作变量 std::atomic_int 是 std::atomic<int> 的别名

void increment(int times)
{
    for (int i = 0; i < times; i++)
    {
        counter++;
    }
}

void safe_increment(int times)
{
    for (int i = 0; i < times; i++)
    {
        // safe_counter_mutex.lock(); // 加锁
        std::lock_guard<std::mutex> lock(safe_counter_mutex);
        safe_counter++;
        // safe_counter_mutex.unlock(); // 释放锁
    }
}

void atomic_increment(int times)
{
    for (int i = 0; i < times; i++)
    {
        atomic_counter++;
    }
}

int main()
{
    std::vector<std::thread> threads;
    std::vector<std::thread> safe_threads;
    std::thread atomic_threads[5]; // 还可以这样用

    // 创建5个线程
    for (int i = 0; i < 5; i++)
    {
        threads.push_back(std::thread(increment, 10000));
        safe_threads.push_back(std::thread(safe_increment, 10000));
    }
    for (std::thread &t : atomic_threads)
    {
        t = std::thread(atomic_increment, 10000);
    }

    // 等待所有线程
    for (auto &t : threads)
        t.join();
    for (auto &t : safe_threads)
        t.join();
    for (auto &t : atomic_threads)
        t.join();

    std::cout << "unsafe expect: 50000, real: " << counter << std::endl;
    std::cout << "safe expect: 50000, real: " << safe_counter << std::endl;
    std::cout << "atomic expect: 50000, real: " << atomic_counter << std::endl;

    return 0;
}